package org.proteored.miapeapi.xml.ms;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.datatype.XMLGregorianCalendar;

import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.exceptions.MiapeDatabaseException;
import org.proteored.miapeapi.exceptions.MiapeSecurityException;
import org.proteored.miapeapi.interfaces.MiapeDate;
import org.proteored.miapeapi.interfaces.Project;
import org.proteored.miapeapi.interfaces.User;
import org.proteored.miapeapi.interfaces.ms.Acquisition;
import org.proteored.miapeapi.interfaces.ms.DataAnalysis;
import org.proteored.miapeapi.interfaces.ms.InstrumentConfiguration;
import org.proteored.miapeapi.interfaces.ms.MSAdditionalInformation;
import org.proteored.miapeapi.interfaces.ms.MSContact;
import org.proteored.miapeapi.interfaces.ms.MiapeMSDocument;
import org.proteored.miapeapi.interfaces.ms.ResultingData;
import org.proteored.miapeapi.interfaces.ms.Spectrometer;
import org.proteored.miapeapi.interfaces.persistence.MiapePersistenceManager;
import org.proteored.miapeapi.interfaces.persistence.PersistenceManager;
import org.proteored.miapeapi.interfaces.xml.MiapeXmlFile;
import org.proteored.miapeapi.interfaces.xml.XmlMiapeFactory;
import org.proteored.miapeapi.validation.ValidationReport;
import org.proteored.miapeapi.validation.ms.MiapeMSValidator;
import org.proteored.miapeapi.xml.miapeproject.UserImpl;
import org.proteored.miapeapi.xml.ms.adapter.ResultingDataAdapter;
import org.proteored.miapeapi.xml.ms.autogenerated.MIAPEContactType;
import org.proteored.miapeapi.xml.ms.autogenerated.MIAPEProject;
import org.proteored.miapeapi.xml.ms.autogenerated.MSAcquisition;
import org.proteored.miapeapi.xml.ms.autogenerated.MSDataAnalysis;
import org.proteored.miapeapi.xml.ms.autogenerated.MSInstrumentConfiguration;
import org.proteored.miapeapi.xml.ms.autogenerated.MSMIAPEMS;
import org.proteored.miapeapi.xml.ms.autogenerated.MSResultingData;
import org.proteored.miapeapi.xml.ms.autogenerated.MSSpectrometer;
import org.proteored.miapeapi.xml.ms.autogenerated.ObjectFactory;
import org.proteored.miapeapi.xml.ms.autogenerated.ParamType;
import org.proteored.miapeapi.xml.ms.util.MsControlVocabularyXmlFactory;

public class MiapeMSDocumentImpl implements MiapeMSDocument {
	private final MSMIAPEMS miapeMsXML;
	private PersistenceManager dbManager;
	private final User user;
	private final XmlMiapeFactory<MiapeMSDocument> xmlFactory;
	private ControlVocabularyManager cvUtil;
	private String name;

	public MiapeMSDocumentImpl(MSMIAPEMS msmiapems, User owner,
			ControlVocabularyManager controlVocabularyUtil, String userName,
			String password) {
		miapeMsXML = msmiapems;
		if (owner != null)
			user = owner;
		else {
			final MIAPEProject miapeProject = msmiapems.getMIAPEProject();
			if (msmiapems != null && miapeProject != null) {
				final String ownerName = miapeProject.getOwnerName();
				if (ownerName != null && password != null)
					user = new UserImpl(ownerName, userName, password);
				else
					user = null;
			} else
				user = null;
		}
		xmlFactory = MiapeMSXmlFactory.getFactory();

		cvUtil = controlVocabularyUtil;
	}

	public MiapeMSDocumentImpl(MSMIAPEMS msmiapems,
			ControlVocabularyManager controlVocabularyUtil,
			PersistenceManager dbManager, String userName, String password)
			throws MiapeDatabaseException, MiapeSecurityException {
		this(msmiapems, dbManager.getUser(userName, password),
				controlVocabularyUtil, userName, password);
		this.dbManager = dbManager;
		cvUtil = controlVocabularyUtil;
	}

	public void setDatabaseManager(PersistenceManager dbManager) {
		this.dbManager = dbManager;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public Set<Acquisition> getAcquisitions() {
		Set<Acquisition> setOfAcquisitions = new HashSet<Acquisition>();

		List<MSAcquisition> acquisitionList = miapeMsXML.getMSAcquisition();
		if (acquisitionList != null) {
			for (MSAcquisition controlAnalysisSoftwareItem : acquisitionList) {
				setOfAcquisitions.add(new AcquisitionImpl(
						controlAnalysisSoftwareItem));
			}
			return setOfAcquisitions;
		}
		return null;
	}

	@Override
	public Set<DataAnalysis> getDataAnalysis() {
		Set<DataAnalysis> setOfPeakListGeneration = new HashSet<DataAnalysis>();

		List<MSDataAnalysis> dataAnalysisList = miapeMsXML.getMSDataAnalysis();
		if (dataAnalysisList != null) {
			for (MSDataAnalysis peakListGenerationItem : dataAnalysisList) {
				setOfPeakListGeneration.add(new DataAnalysisImpl(
						peakListGenerationItem));
			}
			return setOfPeakListGeneration;
		}
		return null;
	}

	/*
	 * @Override public Set<Quantitation> getQuantitations() { Set<Quantitation>
	 * setOfQuantitation = new HashSet<Quantitation>(); List<MSQuantitation>
	 * quantitationList = miapeMsXML.getMSQuantitation(); if (quantitationList
	 * != null) { for (MSQuantitation quantitationItem : quantitationList) {
	 * setOfQuantitation.add(new QuantitationImpl(quantitationItem)); } return
	 * setOfQuantitation; } return null; }
	 */

	@Override
	public Set<Spectrometer> getSpectrometers() {
		Set<Spectrometer> setOfSpectrometers = new HashSet<Spectrometer>();

		List<MSSpectrometer> equipmentList = miapeMsXML.getMSSpectrometer();
		if (equipmentList != null) {
			for (MSSpectrometer spectrometerItem : equipmentList) {
				setOfSpectrometers.add(new SpectrometerImpl(spectrometerItem));
			}
			return setOfSpectrometers;
		}
		return null;
	}

	@Override
	public MSContact getContact() {
		MIAPEContactType msContact = miapeMsXML.getMSContact();
		if (msContact != null)
			return new ContactImpl(msContact);
		return null;
	}

	@Override
	public MiapeDate getDate() {
		String date = miapeMsXML.getDate();
		if (date != null) {
			return new MiapeDate(date);
		}
		return null;
	}

	@Override
	public int getId() {
		return miapeMsXML.getId();
	}

	@Override
	public Date getModificationDate() {
		XMLGregorianCalendar modificationDate = miapeMsXML
				.getModificationDate();
		if (modificationDate != null
				&& modificationDate.toGregorianCalendar() != null) {
			return modificationDate.toGregorianCalendar().getTime();
		}
		return null;
	}

	@Override
	public String getName() {
		if (name != null)
			return name;
		return miapeMsXML.getName();
	}

	@Override
	public User getOwner() {
		return user;
	}

	@Override
	public String getAttachedFileLocation() {
		return miapeMsXML.getAttachedFileLocation();
	}

	@Override
	public Project getProject() {
		if (miapeMsXML.getId() > 0 && dbManager != null) {
			try {
				return dbManager
						.getMiapeMSPersistenceManager()
						.getMiapeById(miapeMsXML.getId(), user.getUserName(),
								user.getPassword()).getProject();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		MIAPEProject project = miapeMsXML.getMIAPEProject();
		if (project != null)
			return new ProjectImpl(project, user, dbManager);

		return null;
	}

	@Override
	public Boolean getTemplate() {
		return miapeMsXML.isTemplate();
	}

	@Override
	public String getVersion() {
		return miapeMsXML.getVersion();
	}

	@Override
	public void delete(String user, String password)
			throws MiapeDatabaseException, MiapeSecurityException {
		MiapePersistenceManager<MiapeMSDocument> miapeMSDatabaseManager = dbManager
				.getMiapeMSPersistenceManager();
		if (dbManager != null && miapeMSDatabaseManager != null) {
			miapeMSDatabaseManager.deleteById(getId(), user, password);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public int store() throws MiapeDatabaseException, MiapeSecurityException {
		if (dbManager != null
				&& dbManager.getMiapeMSPersistenceManager() != null) {
			return dbManager.getMiapeMSPersistenceManager().store(this);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public MiapeXmlFile<MiapeMSDocument> toXml() {
		if (xmlFactory != null) {
			return xmlFactory.toXml(this, cvUtil);
		}
		throw new IllegalMiapeArgumentException(
				"The xml Factory is not defined.");

	}

	@Override
	public String toString() {
		return "MiapeMSDocumentImpl [miapeMsXML=" + miapeMsXML + ", dbManager="
				+ dbManager + ", user=" + user + ", xmlFactory=" + xmlFactory
				+ ", cvUtil=" + cvUtil + "]";
	}

	@Override
	public List<ResultingData> getResultingDatas() {
		List<ResultingData> result = new ArrayList<ResultingData>();
		List<MSResultingData> resultingDataList = miapeMsXML
				.getMSResultingData();
		if (resultingDataList != null) {
			for (MSResultingData resultingDataItem : resultingDataList) {
				result.add(new ResultingDataImpl(resultingDataItem));
			}
			return result;
		}
		return null;
	}

	public void setResultingDatas(List<ResultingData> resultingDatas) {
		List<MSResultingData> msResultingData = miapeMsXML.getMSResultingData();
		if (msResultingData != null)
			msResultingData.clear();
		for (ResultingData resultingData : resultingDatas) {
			ObjectFactory factory = new ObjectFactory();
			MsControlVocabularyXmlFactory cvFactory = new MsControlVocabularyXmlFactory(
					factory, cvUtil);
			miapeMsXML.getMSResultingData().add(
					new ResultingDataAdapter(resultingData, factory, cvFactory)
							.adapt());
		}

	}

	@Override
	public List<MSAdditionalInformation> getAdditionalInformations() {
		List<MSAdditionalInformation> setOfAdditionalInformation = new ArrayList<MSAdditionalInformation>();
		List<ParamType> additionalInformationList = miapeMsXML
				.getMSAdditionalInformation();
		if (additionalInformationList != null) {
			for (ParamType msAdditionalInformation : additionalInformationList) {
				setOfAdditionalInformation.add(new AdditionalInformationImpl(
						msAdditionalInformation));
			}
			return setOfAdditionalInformation;
		}
		return null;
	}

	@Override
	public ValidationReport getValidationReport() {
		return MiapeMSValidator.getInstance().getReport(this);
	}

	@Override
	public List<InstrumentConfiguration> getInstrumentConfigurations() {
		List<InstrumentConfiguration> instrumentConfigurations = new ArrayList<InstrumentConfiguration>();
		List<MSInstrumentConfiguration> msInstrumentConfiguration = miapeMsXML
				.getMSInstrumentConfiguration();
		if (msInstrumentConfiguration != null) {
			for (MSInstrumentConfiguration xmlInstrumentConfiguration : msInstrumentConfiguration) {
				instrumentConfigurations.add(new InstrumentConfigurationImpl(
						xmlInstrumentConfiguration));
			}
			return instrumentConfigurations;
		}
		return null;
	}
}
